package com.lxm.ymcc.service.impl;

import com.alibaba.druid.support.logging.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.lxm.ymcc.EsSearchServerFeign;
import com.lxm.ymcc.constant.CourseConstant;
import com.lxm.ymcc.constents.MqConstants;
import com.lxm.ymcc.constents.RedisConstents;
import com.lxm.ymcc.domain.*;
import com.lxm.ymcc.dto.*;
import com.lxm.ymcc.exlipus.GlobalException;
import com.lxm.ymcc.feginClient.MediaFileServerFeign;
import com.lxm.ymcc.mapper.CourseMapper;
import com.lxm.ymcc.mapper.CourseTeacherMapper;
import com.lxm.ymcc.mapper.TeacherMapper;
import com.lxm.ymcc.result.JSONResult;
import com.lxm.ymcc.service.*;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.lxm.ymcc.util.AssertUtil;
import com.lxm.ymcc.util.StrUtils;
import com.sun.org.apache.bcel.internal.generic.NEW;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.bouncycastle.jcajce.provider.symmetric.TEA;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import springfox.documentation.spring.web.json.Json;

import java.math.BigDecimal;
import java.sql.Struct;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author whale
 * @since 2022-10-23
 */
@Service
@Slf4j
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    @Autowired
    private ITeacherService teacherService;
    @Autowired
    private ICourseDetailService DetailService;
    @Autowired
    private ICourseMarketService marketService;
    @Autowired
    private ICourseResourceService resourceService;
    @Autowired
    private ICourseTeacherService courseTeacherService;
    @Autowired
    private ICourseSummaryService summaryService;
    @Autowired
    private EsSearchServerFeign searchServerFeign;

    @Autowired
    private ICourseChapterService courseChapterService;

    @Autowired
    private MediaFileServerFeign mediaFileServerFeign;


    @Override
    public void insert(CousreParmDto dto) {
        Course course = dto.getCourse();
        CourseDetail courseDetail = dto.getCourseDetail();
        CourseMarket courseMarket = dto.getCourseMarket();
        CourseResource courseResource = dto.getCourseResource();
        List<Long> teacherIds = dto.getTeacherIds();

        // 添加课程表 上线 1 下线 0
        course.setStatus(CourseConstant.STATUS_OFFLINE);
        // 查询老师名字
        EntityWrapper<Teacher> query = new EntityWrapper<>();
        // 相当于where in （1，2）
        query.in("id", teacherIds);
        List<Teacher> teachers = teacherService.selectList(query);
        // 映射
        String teacherNames = teachers.stream().map(teacher -> teacher.getName()).collect(Collectors.joining(","));
        course.setTeacherNames(teacherNames);
        // 添加到course表中
        insert(course);

        // 添加到课程详情表中
        courseDetail.setId(course.getId());
        DetailService.insert(courseDetail);

        // 添加到课程营销表
        courseMarket.setId(course.getId());
        marketService.insert(courseMarket);

        // 添加到课程资源表
        courseResource.setCourseId(course.getId());
        resourceService.insert(courseResource);

        // 添加课程讲师中间表
        teacherIds.forEach(teacherId -> {
            CourseTeacher ct = new CourseTeacher();
            ct.setCourseId(course.getId());
            ct.setTeacherId(teacherId);
            courseTeacherService.insert(ct);
        });

        // 保存到课程汇总表
        CourseSummary courseSummary = new CourseSummary();
        courseSummary.setId(course.getId());
        summaryService.insert(courseSummary);


    }

    /*课程上架 方法
        //1.根据id查找对应Course
        //2.数据校验【数据非空】
        //3.根据id查找t_courseMarket
        //4.根据id查找CourseSummary
        //5.更新Course对象状态
        //6.发起远程调用保存到es
    * */
    @Override
    public void onLineCourse(Long id) {
        //1.根据id查找对应Course
        Course course = selectById(id);
        //2.数据校验【数据非空】
        AssertUtil.isNotNull(course, "非法的请求参数");
        CourseDoc courseDoc = new CourseDoc();

        //3.根据id查找t_courseMarket
        CourseMarket courseMarket = marketService.selectById(id);
        courseDoc.setChargeName(courseMarket.getCharge() == 1 ? "免费" : "收费");

        //4.根据id查找CourseSummary
        CourseSummary courseSummary = summaryService.selectById(id);

        //5.更新Course对象状态
        course.setOnlineTime(new Date());
        course.setStatus(1);
        updateById(course);
        //数据的拷贝
        BeanUtils.copyProperties(course, courseDoc);
        BeanUtils.copyProperties(courseMarket, courseDoc);
        BeanUtils.copyProperties(courseSummary, courseDoc);
        //6.发起远程调用保存到es
        searchServerFeign.save(courseDoc);

        //7.发送站内信
        sendMQ(courseDoc);
    }

    @Override
    public void offLineCourse(Long id) {
        //1.根据id查找对应Course
        Course course = selectById(id);

        //5.更新Course对象状态
        course.setOnlineTime(new Date());
        course.setStatus(0);
        updateById(course);
        //6.发起远程调用删除es
        searchServerFeign.del(id);


    }


    @Autowired
    private RocketMQTemplate template;

    //站内信消息放到mq里面
    public void sendMQ(CourseDoc courseDoc) {
        //1.数据查询要发送的用户的集合  1L 2L 3L... 10L
        List<Long> userIds = Arrays.asList(1L, 2L, 3L);
        //组装消息对象
        String content = "亲爱的用户您好，最新课程  <a href='http://course.ymcc.com:6002/detail.html?courseId=s%%'> s%% </a> 发布啦，点击课程了解详情";
        content = String.format(content, courseDoc.getId(), courseDoc.getName());
        StanionMqDto dto = new StanionMqDto("课程发布啦", content, "系统消息", userIds);
        String jsonString = JSON.toJSONString(dto);

        Message<String> message = MessageBuilder.withPayload(jsonString).build();
        SendResult sendResult = template.syncSend(MqConstants.STANTIC_TOPIC + ":" + MqConstants.STANTIC_TAGES, message);
        log.info("课程站内信发布", sendResult);
    }


    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public String listForUser(InvitationCodeDto invitationCodeDto) {
        //2.准备一个验证码
        String code = StrUtils.getRandomString(4);
        //存放在redis里面的key
        String key = RedisConstents.REG_IN_REDIS_PREFIX + invitationCodeDto.getCode();
        //检查redis里面是否已经存放过
        RegisterCodeInRedis codeInRedis = (RegisterCodeInRedis) redisTemplate.opsForValue().get(key);
        //3.存储到redis里面
        /*
            3.1 导包
            3.2 配置yml
            3.3 注入redisTemplate对象
            3.4 组装key和 code
         */
        //创建一个验证码放到redis里面
        RegisterCodeInRedis newCodeInRedis = new RegisterCodeInRedis(code, System.currentTimeMillis());
        redisTemplate.opsForValue().set(key, newCodeInRedis, 30, TimeUnit.MINUTES);

        return code;
    }


    /**
     * 课程资源视频
     */
             /*
        1.数据的验证  id
        2.根据id查询Course
        3.验证课程状态数据是否存在
        4.查询营销数据CourseMarket
        5.查询课程详情
        6.查询课程对应的老师【根据课程id找中间表，根据中间表找Teacher表】
      7.根据课程找对应的章节
        7.1 找到对应的媒体数据【根据课程查-->List 就是本课程下面所有的媒体数据】
        7.2 把所有的章节转换为 map<id，章节自己>
                7.3 循环变量媒体的list-->媒体数据找到自己所属的章节，添加进去
                [排序要么交给前端，要么自己写]
     */
    @Override
    public CourseDetailVo courseDetail(Long id) {
        // 1.验证数据是否存在
        AssertUtil.isNotNull(id, "数据不存在");

        // 2.根据id查询课程
        Course course = selectById(id);

        // 3.验证课程状态数据是否存在
        AssertUtil.isNotNull(course, "课程不存在");
        AssertUtil.isEqualsTrim(course.getStatus(), Course.STATUS_ONLINE, "课程未上线");

        //  4.查询营销数据CourseMarket
        CourseMarket courseMarket = marketService.selectById(id);

        // 5.查询课程详情
        CourseDetail courseDetail = DetailService.selectById(id);

        //  6.查询课程对应的老师【根据课程id找中间表，根据中间表找Teacher表】
        List<Teacher> teachers = selectTeacherByCourseId(id);

        List<CourseChapter> courseChapters = selectChapter(id);

        return new CourseDetailVo(course, courseDetail, courseMarket, teachers, courseChapters);
    }
@Autowired
private ICourseUserLearnService courseUserLearnService;
    @Override
    public CourseStateVo courseStateById(Long id) {

        AssertUtil.isNotNull(id,"非法的请求");
        //1.查询Course表 检查课程状态
        Course course = selectById(id);
        //2.查询营销表 课程是否免费
        CourseMarket courseMarket = marketService.selectById(id);
        //3.要用户是否购买的此课程
        //3.1 获取当前的登录用户
        Long loginId = 3L;

        Wrapper<CourseUserLearn> wrapper = new EntityWrapper<>() ;
        wrapper.eq("login_id",loginId);
        wrapper.eq("course_id",id);
        CourseUserLearn courseUserLearn = courseUserLearnService.selectOne(wrapper);
        //检查课程是否上线
        boolean isOnline = course.getStatus()==Course.STATUS_ONLINE;
        //检查课程是否免费
        boolean isFree = courseMarket.getCharge()==1;
        //用户是否购买
        boolean isBuy = courseUserLearn!=null&&courseUserLearn.getState()!=1;

        return new CourseStateVo(isFree,isOnline,isBuy);
    }



    private List<CourseChapter> selectChapter(Long id) {
        // 找到课程对应的章节
        EntityWrapper<CourseChapter> wrapper = new EntityWrapper<>();
        wrapper.eq("course_id", id);
        List<CourseChapter> courseChapters = courseChapterService.selectList(wrapper);
        // 把所有的章节转换为map（id,章节自己）
        Map<Long, CourseChapter> collect = courseChapters.stream().collect(Collectors.toMap(CourseChapter::getId, courseChapter -> courseChapter));
        //  7.3 循环变量媒体的list-->媒体数据找到自己所属的章节，添加进去 [排序要么交给前端，要么自己写]
        JSONResult jsonResult = mediaFileServerFeign.selectByCourseId(id);

        AssertUtil.isTrue(jsonResult.isSuccess(), jsonResult.getMessage());

        String jsonString = JSON.toJSONString(jsonResult.getData());

        List<MediaFile> mediaFiles = JSON.parseArray(jsonString, MediaFile.class);
        mediaFiles.forEach(mediaFile -> {
            //清空视频播放地址

            CourseChapter courseChapter = collect.get(mediaFile.getChapterId());
            if (courseChapter != null) {
                courseChapter.getMediaFiles().add(mediaFile);
            }
        });
        return courseChapters;


    }

    private List<Teacher> selectTeacherByCourseId(Long id) {
        EntityWrapper<CourseTeacher> wrapper = new EntityWrapper<>();
        wrapper.eq("course_id", id);
        List<CourseTeacher> courseTeachers = courseTeacherService.selectList(wrapper);
        // 遍历获取集合里所有的老师
        List<Long> collect = courseTeachers.stream().map(CourseTeacher::getTeacherId).collect(Collectors.toList());
        List<Teacher> teachers = teacherService.selectBatchIds(collect);
        return teachers;
    }


    /**
     * 获取购买的课程
     * @param id
     * @return
     */
    @Override
    public CourseOrderDataVo courseInfo(String id) {
        // 1.对于请求的数据 进行校验
        AssertUtil.isNotEmpty(id,"非法请求");
        // 2.对数据进行分割处理
        List<Long> longs = StrUtils.splitStr2LongArr(id);
        // 3.去course表里面找出所有的id 对应Course
        List<Course> courses = selectBatchIds(longs);
        if (courses==null || courses.size()==0) throw new GlobalException("课程未上线");
        // 4.去market表里面找到所有的id 对应CourseMarket
        List<CourseMarket> courseMarkets = marketService.selectBatchIds(longs);
        //5.把markets 转换为map  ,遍历courses
        Map<Long, CourseMarket> marketMap = courseMarkets.stream().collect(Collectors.toMap(CourseMarket::getId, courseMarket -> courseMarket));
        // 6.准备一个集合  将数据添加进去
        ArrayList<CourseItemVo> list = new ArrayList<>();
        //7.计算总金额
        BigDecimal total = new BigDecimal(0);

        for (Course cours : courses) {
            CourseMarket Market = marketMap.get(cours.getId());
            list.add(new CourseItemVo(cours,Market));
            total = total.add(Market.getPrice());
        }
        return new CourseOrderDataVo(list,total);
    }

}



